home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / vh-1_5.lha / vh-1.5 / screen.c < prev    next >
C/C++ Source or Header  |  1993-05-11  |  25KB  |  1,195 lines

  1. /*****************************************************************************
  2.  
  3. NAME
  4.    screen.c -- augmented pseudo-curses(3) screen support
  5.  
  6. SYNOPSIS
  7.    int LINES, COLS;        -- terminal depth & width globals
  8.  
  9.    int initscr()        -- init screen, set LINES and COLS
  10.    int endwin()            -- de-initialize screen code
  11.    int clear()            -- clear screen
  12.    int refresh()        -- refresh real screen from virtual screen
  13.    int ungetch(c)        -- put c on queue to be grabbed by next getch()
  14.    int inch()            -- get char from current update location.
  15.    int move(y, x)        -- move update cursor to row y colum x
  16.    int addch(c)            -- add char c at update location
  17.    int addstr(s)                -- write string from update location
  18.    int attrset(a)        -- set attribute (A_NORMAL, A_REVERSE, A_BOLD)
  19.    bool has_color()        -- do we have color?
  20.    int napms()            -- nap for some number of milliseconds
  21.    void beep();            -- beep the terminal bell
  22.  
  23.    int egetch()            -- get mouse event or character, no echo
  24.    void readscr(lx,ly,rx,ry, s)    -- get content of screen line
  25.  
  26.    bool has_mouse()        -- is there a mouse?
  27.    void mouse_init()        -- initialize mouse
  28.    int mouse_status(py,px)    -- get mouse location and button state
  29.    void mouse_show()        -- show mouse cursor
  30.    void mouse_hide()        -- hide mouse cursor
  31.  
  32. DESCRIPTION
  33.    The idea here is to present a system-independent interface that looks like
  34. a subset of curses(3), with a minimum of hooks for mouse handling and one
  35. concession to Borland C for optimizations's sake.
  36.  
  37.    The addch() and addstr() functions move the update cursor to the right after
  38. writing.  The argument of addch() may have an attribute logical-or'ed in.
  39. The inch() call returns a char with attribute or'ed in; A_CHARTEXT masks out
  40. the character only. The following special keycap defines are used:
  41.  
  42.    KEY_HELP        -- not on PC keyboard
  43.    KEY_REFRESH        -- not on PC keyboard
  44.    KEY_NPAGE        -- PgDn
  45.    KEY_PPAGE        -- PgUp
  46.    KEY_UP        -- Up Arrow
  47.    KEY_DOWN        -- Down Arrow
  48.    KEY_REFERENCE    -- not on PC keyboard
  49.    KEY_ENTER        -- Enter
  50.    KEY_RIGHT        -- Right Arrow
  51.    KEY_LEFT        -- Left Arrow
  52.    KEY_FIND        -- not on PC keyboard
  53.    KEY_SFIND        -- not on PC keyboard
  54.    KEY_SELECT        -- not on PC keyboard
  55.    KEY_HOME        -- Home
  56.    KEY_BEG        -- not on PC keyboard
  57.    KEY_END        -- End
  58.    KEY_UNDO        -- not on PC keyboard
  59.    KEY_PRINT        -- not on PC keyboard
  60.    KEY_MOUSE        -- mouse event happened (not supported by curses(3))
  61.  
  62. Mouse state defines returned by mouse_status():
  63.  
  64.    LEFT_DOWN        -- left mouse button down
  65.    LEFT_UP        -- left mouse button release
  66.    RIGHT_DOWN        -- right mouse button down
  67.    RIGHT_UP        -- right mouse button up
  68.  
  69. Special mouse coordinate values:
  70.  
  71.    CMDLINE        -- command line of application window
  72.    THUMBCOL        -- thumb column of application window
  73.  
  74. BUGS
  75.    The MS-DOS implementation doesn't do optimization for the 
  76. scrolling case.
  77.  
  78. AUTHORS
  79.    Package interface design and UNIX curses(3) code by Eric S. Raymond.
  80.    MS-DOS code by Raymond D. Gardner.
  81.    Please see the READ.ME in this directory for license terms.
  82.  
  83. ******************************************************************************/
  84. /* LINTLIBRARY */
  85. #include <assert.h>
  86.  
  87. #include "screen.h"
  88.  
  89. #ifdef CURSES
  90. /*******************************************************************
  91.  *
  92.  * Support for curses(3) under UNIX.
  93.  *
  94.  ******************************************************************/
  95. #ifdef MOUSE
  96. #include <fcntl.h>
  97. #include <sys/mouse.h>
  98.  
  99. /*
  100.  * We want to make the mouse relatively insensitive to small motions.
  101.  * The code ignores all but 1 in MXSCALE horizontal motions and 1 in MYSCALE
  102.  * vertical motions.  The factors differ as they do because most fonts have
  103.  * a roghly 2/1 aspect ratio; thus, to get the same real rate of vertical
  104.  * motion as horizontal, MYSCALE should be twice as large.
  105.  */
  106. #define MXSCALE    2
  107. #define MYSCALE (MXSCALE * 2)
  108.  
  109. static int mousefd;    /* mouse file descriptir */
  110. static int msy, msx;    /* current mouse coordinates */ 
  111. static int mstat;    /* current mouse status */
  112. static bool mvis = TRUE;    /* should cursor be visible? */
  113. static bool mcolor;    /* show mouse cursor in color? */
  114. #endif /* MOUSE */
  115.  
  116. void mouse_init()
  117. /* initialize the mouse */
  118. {
  119. #ifdef MOUSE
  120.     /*
  121.      * If there's an active mouse, set O_NODELAY on input so we
  122.      * can alternate polling for keystrokes and mouse events without
  123.      * blocking.
  124.      */
  125.     if ((mousefd = open("/dev/mouse", O_RDONLY)) != ERR)
  126.     nodelay(stdscr, TRUE);
  127. #endif /* MOUSE */
  128. #ifdef SCROLLBAR
  129.     COLS--;
  130. #endif /* SCROLLBAR */
  131. }
  132.  
  133. void mouse_color(on)
  134. /* should the mouse cursor be in color? */
  135. bool    on;
  136. {
  137. #ifdef MOUSE
  138.     if (on && has_colors())
  139.     init_pair(COLOR_PAIRS - 1, COLOR_BLACK, COLOR_YELLOW);
  140.     mcolor = on;
  141. #endif /* MOUSE */
  142. }
  143.  
  144. void mouse_move(y, x)
  145. /* move the mouse hotspot to a given location */
  146. int    y, x;
  147. {
  148. #ifdef MOUSE
  149.     msy = y;
  150.     msx = x;
  151. #endif /* MOUSE */
  152. }
  153.  
  154. void mouse_show()
  155. {
  156. #ifdef MOUSE
  157.     mvis = TRUE;
  158. #endif /* MOUSE */
  159. }
  160.  
  161. void mouse_hide()
  162. {
  163. #ifdef MOUSE
  164.     mvis = FALSE;
  165. #endif /* MOUSE */
  166. }
  167.  
  168. int mouse_status(py, px)
  169. /* get current mouse status, return coordinates */
  170. int    *py, *px;
  171. {
  172. #ifdef MOUSE
  173.     if (mousefd != ERR)
  174.     {
  175. #ifdef SCROLLBAR
  176.     *px = (msx == COLS) ? THUMBCOL : msx;
  177. #else
  178.     *px = msx;
  179. #endif /* SCROLLBAR */
  180.     *py = msy;
  181.     return(mstat);
  182.     }
  183. #endif /* MOUSE */
  184.     return(*px = *py = ERR);
  185. }
  186.  
  187. static int cgetch()
  188. /* get single character or mouse event */
  189. {
  190. #ifndef MOUSE
  191.     return(getch());
  192. #else
  193. #ifdef ATTMOUSE
  194.     struct mouseinfo m;
  195. #endif /* ATTMOUSE */
  196.     int mchattr, oldx, oldy, oldmy, oldmx;
  197.     int    c;
  198.  
  199.     if (mousefd == ERR)
  200.     return(getch());
  201.  
  202.     if (mvis)
  203.     {
  204.     getyx(stdscr, oldy, oldx);
  205.  
  206.     move(msy, msx);
  207.     mchattr = inch();
  208.     move(msy, msx);
  209.     if (mcolor)
  210.         addch((mchattr & 0xff) | COLOR_PAIR(COLOR_PAIRS - 1));
  211.     else
  212.         addch(mchattr ^ A_REVERSE);
  213.     oldmy = msy; oldmx = msx;
  214.     refresh();
  215.     }
  216.  
  217.     for (;;)
  218.     {
  219.     /* first poll for a character */
  220.     if ((c = getch()) != ERR)
  221.         break;
  222.  
  223.     /* then poll for a mouse event */
  224. #ifdef ATTMOUSE
  225.     (void) ioctl(mousefd, MOUSEIOCREAD, &m);
  226.     if ((m.status &~ MOVEMENT) | m.xmotion | m.ymotion)
  227.     {
  228.         register i, newx, newy;
  229.  
  230.         newx = msx;
  231.         if (m.xmotion < 0)
  232.         for (i = 0; i < -(m.xmotion / MXSCALE); i++)
  233.             if (newx <= 0)
  234.             break;
  235.             else
  236.             newx--;
  237.         if (m.xmotion > 0)
  238.         for (i = 0; i < (m.xmotion / MXSCALE); i++)
  239. #ifdef SCROLLBAR
  240.             if (newx >= COLS)
  241. #else
  242.             if (newx >= COLS - 1)
  243. #endif /* SCROLLBAR */
  244.             break;
  245.             else
  246.             newx++;
  247.         msx = newx;
  248.         newy = msy;
  249.         if (m.ymotion < 0)
  250.         for (i = 0; i < -(m.ymotion / MYSCALE); i++)
  251.             if (newy <= 0)
  252.             break;
  253.             else
  254.             newy--;
  255.         if (m.ymotion > 0)
  256.         for (i = 0; i < (m.ymotion / MYSCALE); i++)
  257.             if (newy >= LINES - 1)
  258.             break;
  259.             else
  260.             newy++;
  261.         msy = newy;
  262.  
  263.         mstat = 0;
  264.         if (m.status & BUT1CHNG)
  265.         if (m.status & BUT1STAT)
  266.             mstat |= BUTTON1_PRESSED;
  267.         else
  268.             mstat |= BUTTON1_RELEASED;
  269.         if (m.status & BUT3CHNG)
  270.         if (m.status & BUT3STAT)
  271.             mstat |= BUTTON3_PRESSED;
  272.         else
  273.             mstat |= BUTTON3_RELEASED;
  274.  
  275.         c = KEY_MOUSE;
  276.         break;
  277.     }
  278.  
  279.     /* keep polling till you get one or the other */
  280.     }
  281. #endif /* ATTMOUSE */
  282.  
  283.     if (mvis)
  284.     {
  285.     move(oldmy, oldmx);
  286.     addch(mchattr);
  287.     move(oldy, oldx);
  288.     }
  289.  
  290.     return(c);
  291. #endif /* MOUSE */
  292. }
  293.  
  294. void readscr(lx, ly, rx, ry, outbuf)
  295. /* get text from screen */
  296. int    lx, ly, rx, ry;
  297. char    *outbuf;
  298. {
  299.     int    x, y;
  300.  
  301.     for (x = lx; x <= rx; x++)
  302.     for (y = ly; y <= ry; y++)
  303.     {
  304.         move(y, x);
  305.         *outbuf++ = inch() & A_CHARTEXT;
  306.     }
  307.     *outbuf = '\0';
  308. }
  309.  
  310. #ifndef A_COLOR
  311. bool has_colors()
  312. {
  313.     return(FALSE);
  314. }
  315.  
  316. int start_color()
  317. {
  318.     /* do nothing */
  319. }
  320. int init_pair(pn, fg, bg)
  321. int pn, fg, bg;
  322. {
  323.     /* do nothing */
  324. }
  325.  
  326. #endif /* A_COLOR */
  327.  
  328. #endif /* CURSES */
  329.  
  330. #ifdef BSD
  331. /*******************************************************************
  332.  *
  333.  * Support for BSD, which is missing some stuff...
  334.  *
  335.  ******************************************************************/
  336.  
  337. int attrset(a)
  338. /* set write attribute for subsequent operations */
  339. chtype    a;
  340. {
  341.     /*
  342.      * It would be real nice to have more attributes supported in here...
  343.      */
  344.     if (a | A_REVERSE)
  345.     standout();
  346.     else
  347.     standend();
  348.     return(OK);
  349. }
  350.  
  351. void beep()
  352. {
  353.     (void) putchar('\007');
  354. }
  355.  
  356. int start_color()
  357. {
  358.     /* do nothing */
  359. }
  360.  
  361. /*ARGSUSED0*/
  362. int init_pair(pn, fg, bg)
  363. int pn, fg, bg;
  364. {
  365.     /* do nothing */
  366. }
  367.  
  368. unsigned char acs_map[] =
  369. {
  370.    /* ACS_BSSB */    '+',
  371.    /* ACS_SSBB */    '+',
  372.    /* ACS_BBSS */    '+',
  373.    /* ACS_SBBS */    '+',
  374.    /* ACS_SBSS */    '|',
  375.    /* ACS_SSSB */    '|',
  376.    /* ACS_SSBS */    '-',
  377.    /* ACS_BSSS */    '-',
  378.    /* ACS_BSBS */    '-',
  379.    /* ACS_SBSB */    '|',
  380.    /* ACS_SSSS */    '+',
  381.    /* ACS_S1 */        '~',    /* scan line 1 */
  382.    /* ACS_S9 */        '_',    /* scan line 9 */
  383.    /* ACS_DIAMOND */    '*',    /* diamond */
  384.    /* ACS_CKBOARD */    '#',    /* checker board */
  385.    /* ACS_DEGREE */    'o',    /* degree symbol */
  386.    /* ACS_PLMINUS */    '#',    /* plus/minus */
  387.    /* ACS_BULLET */    '*',    /* bullet */
  388.    /* ACS_LARROW */    27,    /* arrow pointing left */
  389.    /* ACS_RARROW */    '>',    /* arrow pointing right */
  390.    /* ACS_DARROW */    'V',    /* arrow pointing down */
  391.    /* ACS_UARROW */    '^',    /* arrow pointing up */
  392.    /* ACS_BOARD */    '#',    /* board of squares */
  393.    /* ACS_LANTERN */    '#',    /* lantern symbol */
  394.    /* ACS_BLOCK */    '#',    /* solid square block */
  395. };
  396. #endif /* BSD */
  397.  
  398. #ifdef MSDOS
  399. /*******************************************************************
  400.  *
  401.  * Support for Borland C under MS-DOS
  402.  *
  403.  ******************************************************************/
  404. #include <dos.h>
  405. #include <conio.h>
  406.  
  407. #define GQDEPTH        32    /* depth of character push queue */
  408.  
  409. int LINES, COLS, COLOR_PAIRS, COLORS = 8;
  410.  
  411. /* vtype values */
  412. #define    PGA        (7)
  413. #define    VGA        (6)
  414. #define    MCGA        (5)
  415. #define    EGA        (4)
  416. #define    CGA        (3)
  417. #define    HERC        (2)
  418. #define    MDA        (1)
  419. #define    NONE        (0)
  420. #define    VUNKNOWN    (-1)
  421.  
  422. /* hascolor values: */
  423. #define    COLOR        (2)
  424. #define    MONO        (1)
  425.  
  426. static int hascolor;
  427. static char screensave[MAXROWS*MAXCOLS*2];    /* save user's screen here */
  428.  
  429. int bufseg;        /* vid buffer segment addr for emulating gettext/puttext */
  430.  
  431. #ifdef __TURBOC__
  432. bool has_snowy_CGA = FALSE;
  433. #endif /* __TURBOC__ */
  434.  
  435. int initscr()
  436. {
  437.     union REGS r;
  438.     struct SREGS s;
  439.     int vtype, vchrome, xmode, *mode = &xmode;
  440.  
  441.     /* default assumptions */
  442.     hascolor = 0;
  443.     LINES = 25;
  444.     bufseg = 0xb800;
  445.  
  446.     /* get mode and columns */
  447.     r.h.ah = 0x0F;
  448.     int86(0x10, &r, &r);
  449.     *mode = r.h.al;
  450.     COLS = r.h.ah;
  451.  
  452.     r.x.ax = 0x1200;        /* alternate function select */
  453.     r.x.bx = 0x0010;
  454.     int86(0x10, &r, &r);
  455.     if (r.x.bx != 0x0010)    /* must be pga/vga/mcga/ps2/ega */
  456.     {
  457.     vtype = EGA;        /* provisional assumption */
  458.     hascolor = r.h.bh ? MONO : COLOR;
  459.  
  460.     /* now try for "higher" display than EGA */
  461.  
  462.     r.x.ax = 0x1A00;    /* get display combination */
  463.     int86(0x10, &r, &r);
  464.     if (r.h.al == 0x1A)    /* must be pga/vga/mcga/ps2 */
  465.     {
  466.         switch (r.h.bl)
  467.         {
  468.         case 0: vtype = NONE;    break;
  469.         case 1: vtype = MDA;     break;
  470.         case 2: vtype = CGA;     break;
  471.         case 4: vtype = EGA;     break;
  472.         case 5: vtype = EGA;     break;
  473.         case 6: vtype = PGA;     break;
  474.         case 7: vtype = VGA;     break;
  475.         case 8: vtype = VGA;     break;
  476.         case 0xC:        /* fall through; analog vs. digital display */
  477.         case 0xA: vtype = MCGA;     break;
  478.         case 0xB: vtype = MCGA;     break;
  479.         default:
  480.         vtype = VUNKNOWN;
  481.         break;
  482.         }
  483.     }
  484.  
  485.     /* get number of rows on screen */
  486.     if (vtype == EGA || vtype == MCGA || vtype == VGA)
  487.     {
  488.         segread(&s);
  489.         r.x.ax = 0x1130;    /* get font info */
  490.         r.h.bh = 0;
  491.         int86x(0x10, &r, &r, &s);
  492.         LINES = r.h.dl + 1;
  493.     } 
  494.     else
  495.         LINES = *(int far *)MK_FP(0x40, 0x84);
  496.     }
  497.     else
  498.     {            /* not pga/vga/mcga/ps2/ega */
  499.     if (*mode != 7)
  500.         vtype = CGA;
  501.     else
  502.     {
  503.         vtype = MDA;
  504.         hascolor = MONO;
  505.     }
  506.     }
  507.  
  508.     bufseg = 0xb800;
  509.     if (vtype == MDA || hascolor == MONO)
  510.      bufseg = 0xb000;
  511.  
  512.     gettext(1, 1, COLS, LINES, screensave);    /* save user's screen */
  513. #ifdef SCROLLBAR
  514.     COLS--;
  515. #endif /* SCROLLBAR */
  516.  
  517. #ifdef __TURBOC__
  518.     {
  519.     extern int _video[12];
  520.     if (! has_snowy_CGA)
  521.         _video[5] = 0;
  522.     }
  523. #endif
  524.     return OK;
  525. }
  526.  
  527. #ifdef __ZTC__
  528. /*******************************************************************
  529. *
  530. * gettext()/puttext() -- simulate Borland screen i/o routines
  531. *
  532. *******************************************************************/
  533.  
  534. int puttext(int left, int top, int right, int bot, char *buf)
  535. {
  536.     int cols, row;
  537.     char far *vid;
  538.     char far *vidstart;
  539.     char *lim;
  540.     cols = right - left + 1;
  541.     --left;
  542.     --top;
  543.     vidstart = vid = MK_FP(bufseg, top*160+left*2);
  544.     for ( row = top; row < bot; ++ row )
  545.     {
  546.     for ( lim = buf + cols * 2; buf < lim; )
  547.         *vid++ = *buf++;
  548.     vid = vidstart += 160;
  549.     }
  550.     return 0;
  551. }
  552.  
  553. int gettext(int left, int top, int right, int bot, char *buf)
  554. {
  555.     int cols, row;
  556.     char far *vid;
  557.     char far *vidstart;
  558.     char *lim;
  559.  
  560.     cols = right - left + 1;
  561.     --left;
  562.     --top;
  563.     vidstart = vid = MK_FP(bufseg, top*160+left*2);
  564.     for ( row = top; row < bot; ++ row )
  565.     {
  566.     for ( lim = buf + cols * 2; buf < lim; )
  567.         *buf++ = *vid++;
  568.     vid = vidstart += 160;
  569.     }
  570.     return 0;
  571. }
  572. #endif /* __ZTC__ */
  573.  
  574.  
  575. int endwin()
  576. /* de-initialize window handling */
  577. {
  578. #ifdef SCROLLBAR
  579.     COLS++;
  580. #endif /* SCROLLBAR */
  581.     puttext(1, 1, COLS, LINES, screensave);    /* restore user screen */
  582.     move(LINES-1,0);
  583.     return OK;
  584. }
  585.  
  586. bool has_colors()
  587. /* is color available? */
  588. {
  589.     return(hascolor == COLOR);
  590. }
  591.  
  592. void readscr(int left, int top, int right, int bot, char *buf0)
  593. /* read the text out of screen region into a buffer */
  594. {
  595.     char s[MAXCOLS * 2];
  596.     register char *buf;
  597.     register char *p;
  598.     register int k;
  599.     int size;
  600.  
  601.     buf = buf0;
  602.     k = (bot-top+1)*(right-left+1);
  603.     assert(k <= MAXCOLS);
  604.     gettext(left+1, top+1, right+1, bot+1, s);
  605.     p = s;
  606.     do
  607.     {
  608.     *buf++ = *p;
  609.     p += 2;
  610.     } while ( --k );
  611.     *buf = 0;
  612. }
  613.  
  614. int refresh()
  615. {
  616.     /* do nothing; this is a write-through implementation */
  617.     return OK;
  618. }
  619.  
  620. /********************** mouse routines ************************/
  621.  
  622. static bool mse = FALSE;    /* nonzero iff mouse is present */
  623.  
  624. bool has_mouse()
  625. /* is there a mouse? */
  626. {
  627.     return(mse);
  628. }
  629.  
  630. void mouse_color(on)
  631. /* show mouse cursor in color? */
  632. bool    on;
  633. {
  634.     (void)on;        /* quiet the compiler warning */
  635.     /* do nothing */
  636. }
  637.  
  638. void mouse_init()
  639. /* initialize the mouse */
  640. {
  641.     union REGS r;
  642.     struct SREGS sregs;
  643.  
  644.     segread(&sregs);
  645.     r.x.ax = 0x3533;
  646.     int86x(0x21, &r, &r, &sregs); /* get mouse driver int addr */
  647.     if (sregs.es == 0 && r.x.bx == 0) /* if addr is zero, no mouse */
  648.     return;
  649.  
  650.     /* if addr points to IRET, no mouse */
  651.     if (*(unsigned char far *)MK_FP(sregs.es, r.x.bx) == 0xcf)
  652.     return;
  653.  
  654.     r.x.ax = 0;
  655.     int86(0x33, &r, &r);    /* try to init mouse driver */
  656.     mse = r.x.ax;        /* set mouse status global var */
  657.     mouse_show();
  658. }
  659.  
  660. void mouse_show()
  661. /* turn on the mouse cursor */
  662. {
  663.     union REGS r;
  664.  
  665.     if (mse)
  666.     {
  667.     r.x.ax = 1;
  668.     int86(0x33, &r, &r);
  669.     }
  670. }
  671.  
  672. void mouse_hide()
  673. /* turn off mouse cursor */
  674. {
  675.     union REGS r;
  676.  
  677.     if (mse)
  678.     {
  679.     r.x.ax = 2;
  680.     int86(0x33, &r, &r);
  681.     }
  682. }
  683.  
  684. void mouse_move(y, x)
  685. /* set mouse cursor position (zero-origin coordinates) */
  686. int    y, x;
  687. {
  688.     union REGS r;
  689.  
  690.     if (mse)
  691.     {
  692.     r.x.ax = 4;
  693.     r.x.cx = x << 3;
  694.     r.x.dx = y << 3;
  695.     int86(0x33, &r, &r);
  696.     }
  697. }
  698.  
  699. /******************* screen/cursor routines ****************/
  700.  
  701. static int cury, curx;        /* virtual update cursor */
  702. static chtype cattr;        /* current attribute */
  703. static chtype pairs[64];    /* color pair array */
  704.  
  705. int move(row, col)
  706. /* cursor positioning */
  707. int row, col;
  708. {
  709.     union REGS regs;
  710.  
  711.     mouse_hide();
  712.     regs.h.ah = 2;
  713.     regs.h.bh = 0;
  714.     regs.h.dh = row;
  715.     regs.h.dl = col;
  716.  
  717.     int86(0x10, ®s, ®s);
  718.     mouse_show();
  719.  
  720.     cury = row;
  721.     curx = col;
  722.     return 0;
  723. }
  724.  
  725. int getyx(row, col)
  726. /* get current cursor position */
  727. int *row;
  728. int *col;
  729. {
  730.     *row = cury;
  731.     *col = curx;
  732.     return 0;
  733. }
  734.  
  735. static void scroll(forward, nlines, attr, top, bot, left, right)
  736. /* scroll screen region */
  737. bool forward;
  738. int nlines, attr, top, bot, left, right;
  739. {
  740.     union REGS regs;
  741.  
  742.     mouse_hide();
  743.     regs.h.ah = 6 + !forward;
  744.     regs.h.al = nlines;
  745.     regs.h.bh = attr;
  746.     regs.h.ch = top;
  747.     regs.h.cl = left;
  748.     regs.h.dh = bot;
  749.     regs.h.dl = right;
  750.     int86(0x10, ®s, ®s);
  751.     mouse_show();
  752. }
  753.  
  754. int clear()
  755. {
  756.     scroll(TRUE, 0, pcattr(cattr), 0, LINES - 1, 0, COLS - 1);
  757.     move(0, 0);
  758.     return OK;
  759. }
  760.  
  761. int pcattr(a)
  762. /* map A_* and color attributes to the bits in IBM CGA/EGA attribute words */
  763. chtype a;
  764. {
  765.     chtype attr = 0;
  766.     int p;
  767.  
  768. #ifdef RDGOPT
  769.     static chtype prevarg = -1234;    /* very unlikely first value */
  770.     static int prevattr;
  771.  
  772.     if ( a == prevarg )        /* if same arg as last one ... */
  773.     return prevattr;    /* ... return prev value */
  774.  
  775.     prevarg = a;        /* save for next time */
  776. #endif /* RDGOPT */
  777.  
  778.     if ( ! (a & A_COLOR) )
  779.     {
  780.     /* monochrome attributes */
  781.     attr  = 0x0007;                /* "normal" attr */
  782.     if (a & A_STANDOUT)        attr  = 0x0070;
  783.     if (a & A_REVERSE)        attr  = 0x0070;
  784.     if (a & A_BLINK)        attr |= 0x0080;
  785.     if (a & A_UNDERLINE)        attr |= 0x0001;
  786.     }
  787.     else
  788.     {
  789.     /* color setup */
  790.     if (p = PAIR_NUMBER(a))
  791.         attr |= pairs[p];
  792.     }
  793.     if (a & A_BOLD)        attr |= 0x0008; /* works for color or mono */
  794.  
  795. #ifdef RDGOPT
  796.     prevattr = attr;    /* save for next time */
  797. #endif /* RDGOPT */
  798.  
  799.     return(attr);
  800. }
  801.  
  802. static void swrite(row, col, s0, attr)
  803. /* write data, starting at given row/col, with given attribute */
  804. int row, col;
  805. char *s0;
  806. int attr;
  807. {
  808.     char buf[MAXCOLS * 2];
  809.     register char *s;
  810.  
  811.     ++row;
  812.     ++col;
  813.     s = s0;
  814.     if ( *s )
  815.     {
  816.     register int *p;
  817.     register int n;
  818.     n = strlen(s);
  819.     p = (int *)buf;
  820.     memset(buf, attr, n * 2);
  821.     *(char *)p = *s;
  822.     --n;
  823.     if ( n )
  824.     {
  825.         do
  826.         {
  827.         *(char *)(++p) = *++s;
  828.         } while ( --n );
  829.     }
  830.     ++s;
  831.     }    
  832.  
  833.     mouse_hide();
  834.     if ( s > s0 )
  835.     puttext(col, row, col + (s - s0) - 1, row, buf);
  836.     mouse_show();
  837. }
  838.  
  839. int attrset(a)
  840. /* set write attribute for subsequent operations */
  841. chtype    a;
  842. {
  843.     cattr = a;
  844.     return(OK);
  845. }
  846.  
  847. int start_color()
  848. {
  849.     if (!has_colors())
  850.     return(ERR);
  851.  
  852.     COLOR_PAIRS = sizeof(pairs) / sizeof(int);
  853.  
  854.     return(OK);
  855. }
  856.  
  857. int init_pair(n, fg, bg)
  858. /* initialize a given color pair to given foreground/background combination */
  859. int    n, fg, bg;
  860. {
  861.     /*
  862.      * By a not-so-amazing coincidence, the numbers of the 8 basic
  863.      * curses(3) colors are precisely the RGB bit patters needed
  864.      * to coerce an IBM CGA adapter.
  865.      */
  866.     if (n < COLOR_PAIRS)
  867.     {
  868.     pairs[n] = (bg << 4) | fg;
  869.     return(OK);
  870.     }
  871.     else
  872.     return(ERR);
  873. }
  874.  
  875. int addstr(s)
  876. /* write a string to the screen, advancing the update cursor */
  877. char    *s;
  878. {
  879.     swrite(cury, curx, s, pcattr(cattr));
  880.     curx += strlen(s);
  881.     return(OK);
  882. }
  883.  
  884. int _addch(c)
  885. /* write a character to the screen, advancing the update cursor */
  886. chtype    c;
  887. {
  888.     static char s[2];
  889.     chtype attr;
  890.  
  891.     if ( (attr = c & A_ATTRIBUTES) == 0 )
  892.     attr = cattr;
  893.     s[0] = c;
  894.     swrite(cury, curx, s, pcattr(attr));
  895.     curx++;
  896.     return(OK);
  897. }
  898.  
  899. /*********** keyboard & mouse handling *****************/
  900.  
  901. /* status variables for last mouse event */
  902. static int lastx, lasty;    /* last mouse position */
  903. static int lastevent;    /* last button event */
  904.  
  905. /* We use MSDOS function 6 (direct console i/o) to avoid problems
  906. ** with control-c/control-break checking
  907. */
  908. static int dos06(int ch) /* ch is -1 for input; anything else for output */
  909. {
  910. #define ZFLAG 0x40
  911.     union REGS r;
  912.  
  913.     r.h.ah = 6;
  914.     r.h.dl = ch;
  915.     intdos(&r, &r);
  916.     if ( ch == -1 )
  917.         return r.x.flags & ZFLAG ? -1 : r.h.al;
  918.     else
  919.         return 0;
  920. }
  921.  
  922. static int cinp(int nowait)
  923. {
  924.     int r;
  925.  
  926.     do
  927.     {
  928.         r = dos06(-1);
  929.     } while ( ! nowait && r == -1 );
  930.     if ( r == 0 )
  931.     {
  932.         r = 256 + dos06(-1);
  933.         assert(r > 256);
  934.     }
  935.     else if ( r == -1 )
  936.     {
  937.     r = 0;
  938.     }
  939.     return r;
  940. }
  941.  
  942. static int getkey()
  943. {
  944.     return cinp(FALSE);
  945. }
  946.  
  947. static int getkeynowait()
  948. {
  949.     return cinp(TRUE);
  950. }
  951.  
  952. int mse_status_raw(py, px)
  953. int *px, *py;
  954. {
  955.     union REGS r;
  956.  
  957.     r.x.ax = 3;
  958.     int86(0x33, &r, &r);
  959.     *px = r.x.cx >> 3;    /* translate coords to col/row */
  960.     *py = r.x.dx >> 3;
  961.     return r.x.bx;
  962. }
  963.  
  964. static int cgetch()
  965. /* return next keypress or mouse click */
  966. {
  967.     static int left_was_down = FALSE;
  968.     static int right_was_down = FALSE;
  969.     int code;
  970.  
  971.     /* no mouse? then just get a keystroke */
  972.     if (!mse)
  973.     code = getkey();
  974.     else        /* there's a mouse; wait on event */
  975.     for (;;)
  976.     {
  977.         int x, y, mse_stat;
  978.  
  979.         if (code = getkeynowait())
  980.         break;
  981. #if 00
  982.         mse_stat = mouse_status(&y, &x);
  983. #endif
  984.         /* poll the mouse */
  985.         mse_stat = mse_status_raw(&lasty, &lastx);
  986.         
  987.         if ( mse_stat & 1 )
  988.         {
  989.         if ( ! left_was_down )
  990.         {
  991.             left_was_down = TRUE;
  992.             lastevent = (lastevent & ~ BUTTON1_RELEASED) | BUTTON1_PRESSED;
  993.             return KEY_MOUSE;
  994.         }
  995.         else
  996.         {
  997. #ifdef SCROLLBAR
  998.             napms(150);
  999.             if ( mse_status_raw(&lasty, &lastx) & 1 && lastx == COLS )
  1000.             {
  1001.                 lastevent =
  1002.                 (lastevent & ~ BUTTON1_RELEASED) | BUTTON1_PRESSED;
  1003.                 return KEY_MOUSE;
  1004.             }
  1005. #endif /* SCROLLBAR */
  1006.         }
  1007.         }
  1008.         else
  1009.         {
  1010.         if ( left_was_down )
  1011.         {
  1012.             left_was_down = FALSE;
  1013.             lastevent = (lastevent & ~ BUTTON1_PRESSED) | BUTTON1_RELEASED;
  1014.             return KEY_MOUSE;
  1015.         }
  1016.         else
  1017.             lastevent = 0;
  1018.         }
  1019.  
  1020.         if ( mse_stat & 2 )
  1021.         {
  1022.         if ( ! right_was_down )
  1023.         {
  1024.             right_was_down = TRUE;
  1025.             lastevent = (lastevent & ~ BUTTON3_RELEASED) | BUTTON3_PRESSED;
  1026.             return KEY_MOUSE;
  1027.         }
  1028.         }
  1029.         else
  1030.         {
  1031.         if ( right_was_down )
  1032.         {
  1033.             right_was_down = FALSE;
  1034.             lastevent = (lastevent & ~ BUTTON3_PRESSED) | BUTTON3_RELEASED;
  1035.             return KEY_MOUSE;
  1036.         }
  1037.         else
  1038.             lastevent = 0;
  1039.         }
  1040.  
  1041. #if 00
  1042.         lastevent = 0;
  1043.         if ((mse_stat & 0x01) != left_was_down)
  1044.         {
  1045.         lastevent |= (left_was_down ? BUTTON1_RELEASED : BUTTON1_PRESSED);
  1046.         left_was_down = !left_was_down;
  1047.         return(KEY_MOUSE);
  1048.         }
  1049.  
  1050.         if ((mse_stat & 0x02) != right_was_down)
  1051.         {
  1052.         lastevent |= (right_was_down ? BUTTON3_RELEASED : BUTTON3_PRESSED);
  1053.         right_was_down = !right_was_down;
  1054.         return(KEY_MOUSE);
  1055.         }
  1056. #endif
  1057.     }
  1058.  
  1059.     /* special-key code translation */
  1060.     switch (code)
  1061.     {
  1062.     case 315:    return(KEY_F(1));    /* break; */
  1063.     case 316:    return(KEY_F(2));    /* break; */
  1064.     case 317:    return(KEY_F(3));    /* break; */
  1065.     case 318:    return(KEY_F(4));    /* break; */
  1066.     case 319:    return(KEY_F(5));    /* break; */
  1067.     case 320:    return(KEY_F(6));    /* break; */
  1068.     case 321:    return(KEY_F(7));    /* break; */
  1069.     case 322:    return(KEY_F(8));    /* break; */
  1070.     case 323:    return(KEY_F(9));    /* break; */
  1071.     case 324:    return(KEY_F(10));    /* break; */
  1072.  
  1073.     case 328:    return(KEY_UP);        /* break; */
  1074.     case 336:    return(KEY_DOWN);    /* break; */
  1075.     case 331:    return(KEY_LEFT);    /* break; */
  1076.     case 333:    return(KEY_RIGHT);    /* break; */
  1077.  
  1078.     case 335:    return(KEY_END);    /* break; */
  1079.     case 327:    return(KEY_HOME);    /* break; */
  1080.     case 337:    return(KEY_NPAGE);    /* break; */
  1081.     case 329:    return(KEY_PPAGE);    /* break; */
  1082.  
  1083.     default:        break;
  1084.     }
  1085.     return(code);
  1086. }
  1087.  
  1088. int mouse_status(py, px)
  1089. /* return status caught by last mouse button event */
  1090. int    *py, *px;
  1091. {
  1092.     *py = lasty;
  1093. #ifdef SCROLLBAR
  1094.     *px = (lastx == COLS) ? THUMBCOL : lastx;
  1095. #else
  1096.     *px = lastx;
  1097. #endif /* SCROLLBAR */
  1098.     return(lastevent);
  1099. }
  1100.  
  1101. int inch()
  1102. /* get character and attribute at current update position */
  1103. {
  1104.     char    buf[4];
  1105.  
  1106.     gettext(curx + 1, cury + 1, curx + 1, cury + 1, buf);
  1107.     return(buf[0]);
  1108. }
  1109.  
  1110. #include <time.h>
  1111. #define    millisecs()     ((clock() * 10000)/(int)(double)(0.5+CLK_TCK*10))
  1112.  
  1113. int napms(n)
  1114. /* sleep for n milliseconds */
  1115. int    n;
  1116. {
  1117.     long    t0 = millisecs() + n;
  1118.  
  1119.     while (millisecs() < t0)
  1120.     continue;
  1121.     return(millisecs());
  1122. }
  1123.  
  1124. void beep()
  1125. {
  1126.     (void) putchar('\007');
  1127. }
  1128.  
  1129. unsigned char acs_map[] =
  1130. {
  1131.    /* ACS_BSSB */    218,
  1132.    /* ACS_SSBB */    192,
  1133.    /* ACS_BBSS */    191,
  1134.    /* ACS_SBBS */    217,
  1135.    /* ACS_SBSS */    180,
  1136.    /* ACS_SSSB */    195,
  1137.    /* ACS_SSBS */    193,
  1138.    /* ACS_BSSS */    194,
  1139.    /* ACS_BSBS */    196,
  1140.    /* ACS_SBSB */    179,
  1141.    /* ACS_SSSS */    197,
  1142.    /* ACS_S1 */        223,    /* scan line 1 (actually top-half on) */
  1143.    /* ACS_S9 */        22,    /* scan line 9 */
  1144.    /* ACS_DIAMOND */    254,    /* diamond (actually bullet) */
  1145.    /* ACS_CKBOARD */    178,    /* checker board (stipple) */
  1146.    /* ACS_DEGREE */    248,    /* degree symbol */
  1147.    /* ACS_PLMINUS */    241,    /* plus/minus */
  1148.    /* ACS_BULLET */    254,    /* bullet */
  1149.    /* ACS_LARROW */    27,    /* arrow pointing left */
  1150.    /* ACS_RARROW */    26,    /* arrow pointing right */
  1151.    /* ACS_DARROW */    25,    /* arrow pointing down */
  1152.    /* ACS_UARROW */    24,    /* arrow pointing up */
  1153.    /* ACS_BOARD */    220,    /* board of squares */
  1154.    /* ACS_LANTERN */    15,    /* lantern symbol */
  1155.    /* ACS_BLOCK */    219,    /* solid square block */
  1156. };
  1157. #endif /* MSDOS */
  1158.  
  1159. #if !defined(CURSES) || defined(BSD) || defined(AMIGA)
  1160. /* character push queue */
  1161. static chtype getchq[GQDEPTH];
  1162. static int gqc = 0;
  1163.  
  1164. int egetch()
  1165. /* get single character or mouse event */
  1166. {
  1167.     /* queued characters waiting? then go */
  1168.     if (gqc > 0)
  1169.     return(getchq[--gqc]);
  1170.     else
  1171.     return(cgetch());
  1172. }
  1173.  
  1174. int ungetch(c)
  1175. /* try to queue a character for input */
  1176. int    c;
  1177. {
  1178.     if (gqc >= GQDEPTH)
  1179.     return(ERR);
  1180.     else
  1181.     {
  1182.     getchq[gqc++] = c;
  1183.     return(OK);
  1184.     }
  1185. }
  1186. #else
  1187. int egetch()
  1188. /* get single character or mouse event */
  1189. {
  1190.     return(cgetch());
  1191. }
  1192. #endif /* !defined(CURSES) || defined(BSD) */
  1193.  
  1194. /* screen.c ends here */
  1195.